qcanvas 0.0.5.7a0__py3-none-any.whl → 1.0.3.post0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of qcanvas might be problematic. Click here for more details.
- qcanvas/app_start/__init__.py +47 -0
- qcanvas/backend_connectors/__init__.py +2 -0
- qcanvas/backend_connectors/frontend_resource_manager.py +63 -0
- qcanvas/backend_connectors/qcanvas_task_master.py +28 -0
- qcanvas/icons/__init__.py +6 -0
- qcanvas/icons/file-download-failed.svg +6 -0
- qcanvas/icons/file-downloaded.svg +6 -0
- qcanvas/icons/file-not-downloaded.svg +6 -0
- qcanvas/icons/file-unknown.svg +6 -0
- qcanvas/icons/icons.qrc +4 -0
- qcanvas/icons/main_icon.svg +7 -7
- qcanvas/icons/rc_icons.py +580 -214
- qcanvas/icons/sync.svg +6 -6
- qcanvas/run.py +29 -0
- qcanvas/ui/course_viewer/__init__.py +2 -0
- qcanvas/ui/course_viewer/content_tree.py +123 -0
- qcanvas/ui/course_viewer/course_tree.py +93 -0
- qcanvas/ui/course_viewer/course_viewer.py +62 -0
- qcanvas/ui/course_viewer/tabs/__init__.py +3 -0
- qcanvas/ui/course_viewer/tabs/assignment_tab/__init__.py +1 -0
- qcanvas/ui/course_viewer/tabs/assignment_tab/assignment_tab.py +168 -0
- qcanvas/ui/course_viewer/tabs/assignment_tab/assignment_tree.py +104 -0
- qcanvas/ui/course_viewer/tabs/content_tab.py +96 -0
- qcanvas/ui/course_viewer/tabs/mail_tab/__init__.py +1 -0
- qcanvas/ui/course_viewer/tabs/mail_tab/mail_tab.py +68 -0
- qcanvas/ui/course_viewer/tabs/mail_tab/mail_tree.py +70 -0
- qcanvas/ui/course_viewer/tabs/page_tab/__init__.py +1 -0
- qcanvas/ui/course_viewer/tabs/page_tab/page_tab.py +36 -0
- qcanvas/ui/course_viewer/tabs/page_tab/page_tree.py +74 -0
- qcanvas/ui/course_viewer/tabs/resource_rich_browser.py +176 -0
- qcanvas/ui/course_viewer/tabs/util.py +1 -0
- qcanvas/ui/main_ui/course_viewer_container.py +52 -0
- qcanvas/ui/main_ui/options/__init__.py +3 -0
- qcanvas/ui/main_ui/options/quick_sync_option.py +25 -0
- qcanvas/ui/main_ui/options/sync_on_start_option.py +25 -0
- qcanvas/ui/main_ui/qcanvas_window.py +192 -0
- qcanvas/ui/main_ui/status_bar_progress_display.py +153 -0
- qcanvas/ui/memory_tree/__init__.py +2 -0
- qcanvas/ui/memory_tree/_tree_memory.py +66 -0
- qcanvas/ui/memory_tree/memory_tree_widget.py +133 -0
- qcanvas/ui/memory_tree/memory_tree_widget_item.py +19 -0
- qcanvas/ui/setup/__init__.py +2 -0
- qcanvas/ui/setup/setup_checker.py +17 -0
- qcanvas/ui/setup/setup_dialog.py +212 -0
- qcanvas/util/__init__.py +2 -0
- qcanvas/util/basic_fonts.py +12 -0
- qcanvas/util/fe_resource_manager.py +23 -0
- qcanvas/util/html_cleaner.py +25 -0
- qcanvas/util/layouts.py +52 -0
- qcanvas/util/logs.py +6 -0
- qcanvas/util/paths.py +41 -0
- qcanvas/util/settings/__init__.py +9 -0
- qcanvas/util/settings/_client_settings.py +29 -0
- qcanvas/util/settings/_mapped_setting.py +63 -0
- qcanvas/util/settings/_ui_settings.py +34 -0
- qcanvas/util/ui_tools.py +41 -0
- qcanvas/util/url_checker.py +13 -0
- qcanvas-1.0.3.post0.dist-info/METADATA +61 -0
- qcanvas-1.0.3.post0.dist-info/RECORD +64 -0
- {qcanvas-0.0.5.7a0.dist-info → qcanvas-1.0.3.post0.dist-info}/WHEEL +1 -1
- qcanvas-1.0.3.post0.dist-info/entry_points.txt +3 -0
- qcanvas/__main__.py +0 -155
- qcanvas/db/__init__.py +0 -5
- qcanvas/db/database.py +0 -338
- qcanvas/db/db_converter_helper.py +0 -81
- qcanvas/net/canvas/__init__.py +0 -2
- qcanvas/net/canvas/canvas_client.py +0 -209
- qcanvas/net/canvas/legacy_canvas_types.py +0 -124
- qcanvas/net/custom_httpx_async_transport.py +0 -34
- qcanvas/net/self_authenticating.py +0 -108
- qcanvas/queries/__init__.py +0 -4
- qcanvas/queries/all_courses.gql +0 -7
- qcanvas/queries/all_courses.py +0 -108
- qcanvas/queries/canvas_course_data.gql +0 -51
- qcanvas/queries/canvas_course_data.py +0 -143
- qcanvas/ui/container_item.py +0 -11
- qcanvas/ui/main_ui.py +0 -251
- qcanvas/ui/menu_bar/__init__.py +0 -0
- qcanvas/ui/menu_bar/grouping_preferences_menu.py +0 -61
- qcanvas/ui/menu_bar/theme_selection_menu.py +0 -39
- qcanvas/ui/setup_dialog.py +0 -190
- qcanvas/ui/status_bar_reporter.py +0 -40
- qcanvas/ui/viewer/__init__.py +0 -0
- qcanvas/ui/viewer/course_list.py +0 -96
- qcanvas/ui/viewer/file_list.py +0 -195
- qcanvas/ui/viewer/file_view_tab.py +0 -62
- qcanvas/ui/viewer/page_list_viewer.py +0 -150
- qcanvas/util/app_settings.py +0 -98
- qcanvas/util/constants.py +0 -5
- qcanvas/util/course_indexer/__init__.py +0 -1
- qcanvas/util/course_indexer/conversion_helpers.py +0 -78
- qcanvas/util/course_indexer/data_manager.py +0 -447
- qcanvas/util/course_indexer/resource_helpers.py +0 -191
- qcanvas/util/download_pool.py +0 -58
- qcanvas/util/helpers/__init__.py +0 -0
- qcanvas/util/helpers/canvas_sanitiser.py +0 -47
- qcanvas/util/helpers/file_icon_helper.py +0 -34
- qcanvas/util/helpers/qaction_helper.py +0 -25
- qcanvas/util/helpers/theme_helper.py +0 -48
- qcanvas/util/link_scanner/__init__.py +0 -2
- qcanvas/util/link_scanner/canvas_link_scanner.py +0 -41
- qcanvas/util/link_scanner/canvas_media_object_scanner.py +0 -60
- qcanvas/util/link_scanner/dropbox_scanner.py +0 -68
- qcanvas/util/link_scanner/resource_scanner.py +0 -69
- qcanvas/util/progress_reporter.py +0 -101
- qcanvas/util/self_updater.py +0 -55
- qcanvas/util/task_pool.py +0 -253
- qcanvas/util/tree_util/__init__.py +0 -3
- qcanvas/util/tree_util/expanding_tree.py +0 -165
- qcanvas/util/tree_util/model_helpers.py +0 -36
- qcanvas/util/tree_util/tree_model.py +0 -85
- qcanvas-0.0.5.7a0.dist-info/METADATA +0 -21
- qcanvas-0.0.5.7a0.dist-info/RECORD +0 -62
- /qcanvas/{net → ui/main_ui}/__init__.py +0 -0
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
qcanvas/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
2
|
+
qcanvas/app_start/__init__.py,sha256=eY5J0QuKCx0keX443qA4Fgs6paojxwPOWdD66pBVQ7Q,1078
|
|
3
|
+
qcanvas/backend_connectors/__init__.py,sha256=Wj8cmxQng3SSlmlXJyzHaPmvxbkauwsxINckPb7WuHc,108
|
|
4
|
+
qcanvas/backend_connectors/frontend_resource_manager.py,sha256=EpwsVzA4b6M9y5twn9cG_GujwzwmKxBfdgqPCQ8tB3I,2131
|
|
5
|
+
qcanvas/backend_connectors/qcanvas_task_master.py,sha256=SAZ_7dWsQr35cdkhcbIlkxWbe3C46_vLNThOpvTHIOs,751
|
|
6
|
+
qcanvas/icons/__init__.py,sha256=eaZWyt-xEsLqRVI2HNvevgRhXUnM_oyDrT5hSyLM1eE,246
|
|
7
|
+
qcanvas/icons/file-download-failed.svg,sha256=b1Nx5mW_dbh3nuex4e-11btcGILLg59PHUG5lV6bc2U,1327
|
|
8
|
+
qcanvas/icons/file-downloaded.svg,sha256=ymf1NU5uvKZq41kNVTtKkUoIzUE3pbHmx5IvwPYoyiU,789
|
|
9
|
+
qcanvas/icons/file-not-downloaded.svg,sha256=TVpIZYDUfOw3S0cmXR3FawiCp0Y_PTSR4XKwrsy1qOs,1270
|
|
10
|
+
qcanvas/icons/file-unknown.svg,sha256=9xlN244HJX3zM_MqdMTnNbKlqLjOFgCx3ZdM4Wc4zC0,1729
|
|
11
|
+
qcanvas/icons/icons.qrc,sha256=czwaoP0TNXGoH91cstRbdhvKnfyLlmAp-VmaZoBk0YY,280
|
|
12
|
+
qcanvas/icons/main_icon.svg,sha256=st2sfA8HIETmoacJ2Oq84iJzfnNHH-T03ijB-J419_s,16104
|
|
13
|
+
qcanvas/icons/rc_icons.py,sha256=Ankeu0oWJk-1qLGVLxmiK5Kt1LVNyDmpR8jJZzOG5gQ,18194
|
|
14
|
+
qcanvas/icons/sync.svg,sha256=J-7_KnFbQL3uh-RrTy0_wSJUVW4Cc6ZSTacld6ULv1w,2829
|
|
15
|
+
qcanvas/run.py,sha256=V_ni8SWwh4_GrymX09Yfmd8Pwpz30ohIpDQ6Nk6rQPw,538
|
|
16
|
+
qcanvas/ui/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
17
|
+
qcanvas/ui/course_viewer/__init__.py,sha256=XkoFnh4ULw3_i-GDsOlueEWido0PkoDcN9_EX6-nkXY,76
|
|
18
|
+
qcanvas/ui/course_viewer/content_tree.py,sha256=-W9-pw76j2SHWoFnhLk7DhQxhge_Kh0HHxHYDYsyBeQ,3605
|
|
19
|
+
qcanvas/ui/course_viewer/course_tree.py,sha256=mp2bzqtd9e8TT5_23leR1p-B1IbZbRu9D8fntAIjY5U,2937
|
|
20
|
+
qcanvas/ui/course_viewer/course_viewer.py,sha256=t2RFzGIq_LM3yNNxY0bcNRg6Z0gFoA1iJPy6OSqvOYs,2457
|
|
21
|
+
qcanvas/ui/course_viewer/tabs/__init__.py,sha256=SlfWUzk6_E5uM9GIV-y9BVeKMwqn3pRx_xWhMyb1dfI,54
|
|
22
|
+
qcanvas/ui/course_viewer/tabs/assignment_tab/__init__.py,sha256=w936dW7za10Fh6rN0zVA-7Kyiup3kd6C-mPAFHtxmy0,42
|
|
23
|
+
qcanvas/ui/course_viewer/tabs/assignment_tab/assignment_tab.py,sha256=dt9UtjxDwbmhsVP2dI1uaE2ovPdH7TynR0mkUnOP-so,5630
|
|
24
|
+
qcanvas/ui/course_viewer/tabs/assignment_tab/assignment_tree.py,sha256=O1O3-ZPimjm4xPliVSPUmlKdlIwbUc3oehtmeVfiVdU,3412
|
|
25
|
+
qcanvas/ui/course_viewer/tabs/content_tab.py,sha256=gk2r1UBOyMOXeeTs1zBgsHBKc1oAOeIM75RTE3_mkug,3184
|
|
26
|
+
qcanvas/ui/course_viewer/tabs/mail_tab/__init__.py,sha256=68iRUUWEP7mudbaxa4ZBKMra4rvs2oZKaZkBWwmUrsI,30
|
|
27
|
+
qcanvas/ui/course_viewer/tabs/mail_tab/mail_tab.py,sha256=6VwUyHa5IItHzaSikX-P8IqT_AFcvhLycUIcx-5BeO4,2126
|
|
28
|
+
qcanvas/ui/course_viewer/tabs/mail_tab/mail_tree.py,sha256=zoWz9iWxNhv9fGxpdXMrF6APvMwD9tyQbngTLJlTIhU,2151
|
|
29
|
+
qcanvas/ui/course_viewer/tabs/page_tab/__init__.py,sha256=lcafxlSEVZ0wqZySxT6hTrvExX-GU2AfcZQbp6W8haU,30
|
|
30
|
+
qcanvas/ui/course_viewer/tabs/page_tab/page_tab.py,sha256=uWLiVjrccF-Xyit_BTfQ2GvytVuURidTIPKyJVCMSGw,1079
|
|
31
|
+
qcanvas/ui/course_viewer/tabs/page_tab/page_tree.py,sha256=-waRh47KZajmme-UT4iEetM-skSW2aMuGPxA1Cjkjqs,2579
|
|
32
|
+
qcanvas/ui/course_viewer/tabs/resource_rich_browser.py,sha256=rVeBKjjgE_aT0B7TgBHoJSy2qrHeVagS58YSEK_zaP8,6240
|
|
33
|
+
qcanvas/ui/course_viewer/tabs/util.py,sha256=rUVEGSREV9vTFs4o3AD2OjaSFA-GPsmelxYWz0J8OP4,48
|
|
34
|
+
qcanvas/ui/main_ui/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
35
|
+
qcanvas/ui/main_ui/course_viewer_container.py,sha256=PgqgWoUdP1QoLt1ZSGke6sCLko80FtOIuYrqlIA3ilA,1914
|
|
36
|
+
qcanvas/ui/main_ui/options/__init__.py,sha256=SlfWUzk6_E5uM9GIV-y9BVeKMwqn3pRx_xWhMyb1dfI,54
|
|
37
|
+
qcanvas/ui/main_ui/options/quick_sync_option.py,sha256=qEfmtLllO32ejc-bydCvFRjal5RUlk2HtC5Ld4mT7ss,753
|
|
38
|
+
qcanvas/ui/main_ui/options/sync_on_start_option.py,sha256=zFFAAyGZEa6qBchJJIm7bJpOwxcntnto9Ee-lzCiHX4,731
|
|
39
|
+
qcanvas/ui/main_ui/qcanvas_window.py,sha256=Za2uzvK64mX1-KoHyjK04o3Cf2ckMcIYJjuZ0zndtKQ,6713
|
|
40
|
+
qcanvas/ui/main_ui/status_bar_progress_display.py,sha256=rYvrwG0FAMzUuKiFvnjYv3YSlYQYG-K9MKeAvP5UIzU,4833
|
|
41
|
+
qcanvas/ui/memory_tree/__init__.py,sha256=-XLitM6teC0zmwPrGf-Q-A53-zgmIPASExdOtaLIvPU,107
|
|
42
|
+
qcanvas/ui/memory_tree/_tree_memory.py,sha256=CMKfCnrHj22ervaq7xB5U4AiKijYvghUK5ZL0MJIFmQ,1805
|
|
43
|
+
qcanvas/ui/memory_tree/memory_tree_widget.py,sha256=NOug0yjzX-woSDqv2HK1-HFf6cJxdGeIwebz2QaSB-Q,4402
|
|
44
|
+
qcanvas/ui/memory_tree/memory_tree_widget_item.py,sha256=JXk07AzrKsBnYAqhayIFYAwMfF_D_EfkfJY4Qyez47U,425
|
|
45
|
+
qcanvas/ui/setup/__init__.py,sha256=QWt2lEyLqWG5QC-BmCBlYyi0LZsBfsQYbP0XkvqA2f8,77
|
|
46
|
+
qcanvas/ui/setup/setup_checker.py,sha256=ysQpkVLIWn8BR3hKhekuRIsHNAOU-jnHm061dfQ_OcY,396
|
|
47
|
+
qcanvas/ui/setup/setup_dialog.py,sha256=rl5B3AsNcV-QNeGw3xKnEP87Giyug5hsW8mhU3S8IUM,7881
|
|
48
|
+
qcanvas/util/__init__.py,sha256=RmC5zxGHoTLudrx9uol55fM5dvIkFjBCroQGYXaELCA,51
|
|
49
|
+
qcanvas/util/basic_fonts.py,sha256=1NK5_kejgH45mENwiTWvE5oOuAvGqWMX3hg9tTUCBi4,243
|
|
50
|
+
qcanvas/util/fe_resource_manager.py,sha256=5YO549oBpSgcthD9hxm8trnjHEfudltkh-SfqlOa9xA,808
|
|
51
|
+
qcanvas/util/html_cleaner.py,sha256=O9_PhvZZw3RcPjdXZagAbNmp8Hfyq9fydBH-ee-DfII,615
|
|
52
|
+
qcanvas/util/layouts.py,sha256=7wQ0-DAbRHPPcfVIQoOmVhPdhGqcF-6qWE1-P86e7ys,1351
|
|
53
|
+
qcanvas/util/logs.py,sha256=VZKFITiW2WR2POEFVv5GRpEXic23Pzjehry-vH3g3Gk,138
|
|
54
|
+
qcanvas/util/paths.py,sha256=HGIOqplZykmGBNaUaNFIik_Tj4jLAi4n-TZbvUIivDE,1035
|
|
55
|
+
qcanvas/util/settings/__init__.py,sha256=ivc8bczhQdEJsWse6fc81Xyz0i2YX57pL4UubM3NJfw,228
|
|
56
|
+
qcanvas/util/settings/_client_settings.py,sha256=HxGH9eOCdBj8wYboGhzNX0LFw_bmzF-Vwo44y1W0EqY,1036
|
|
57
|
+
qcanvas/util/settings/_mapped_setting.py,sha256=1zQAfXxWB9yUtWCBObnOZl7EQ22bS-4u2yGGGSdhKJo,1792
|
|
58
|
+
qcanvas/util/settings/_ui_settings.py,sha256=X1AFVIJzck0S3YdEWN6VMws4k9sWquM1t5hwMYOsfTw,927
|
|
59
|
+
qcanvas/util/ui_tools.py,sha256=bSM1xrmZPn847YEbXAC9VIAv--8hMLMWrsEMWGA5p3E,916
|
|
60
|
+
qcanvas/util/url_checker.py,sha256=03jqnQ1_GOlCJyRHrlMbSQE9QsHrVNsg0kFsA8oKP60,361
|
|
61
|
+
qcanvas-1.0.3.post0.dist-info/METADATA,sha256=NoCI4QeObT-imY9XOKjGS87Lc0Mkvg8v6OgRq4h3J54,1643
|
|
62
|
+
qcanvas-1.0.3.post0.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
|
|
63
|
+
qcanvas-1.0.3.post0.dist-info/entry_points.txt,sha256=46VbnhQ9w2CYdfhYcPfWgjXYHjsKshu0asQ1B_sAMac,44
|
|
64
|
+
qcanvas-1.0.3.post0.dist-info/RECORD,,
|
qcanvas/__main__.py
DELETED
|
@@ -1,155 +0,0 @@
|
|
|
1
|
-
import asyncio
|
|
2
|
-
import logging
|
|
3
|
-
import sys
|
|
4
|
-
|
|
5
|
-
import httpx
|
|
6
|
-
from PySide6.QtCore import Signal
|
|
7
|
-
from PySide6.QtGui import QPixmap
|
|
8
|
-
from PySide6.QtWidgets import QApplication, QProgressDialog, QMainWindow
|
|
9
|
-
from httpx import URL
|
|
10
|
-
from qasync import QEventLoop, asyncSlot
|
|
11
|
-
from sqlalchemy.ext.asyncio import create_async_engine
|
|
12
|
-
from sqlalchemy.ext.asyncio.session import async_sessionmaker as AsyncSessionMaker
|
|
13
|
-
|
|
14
|
-
import qcanvas.db as db
|
|
15
|
-
# noinspection PyUnresolvedReferences
|
|
16
|
-
import qcanvas.icons
|
|
17
|
-
from qcanvas.net.canvas.canvas_client import CanvasClient
|
|
18
|
-
from qcanvas.ui.main_ui import AppMainWindow
|
|
19
|
-
from qcanvas.ui.setup_dialog import SetupDialog
|
|
20
|
-
from qcanvas.util import self_updater
|
|
21
|
-
from qcanvas.util.app_settings import settings
|
|
22
|
-
from qcanvas.util.constants import app_name, updated_and_needs_restart_return_code
|
|
23
|
-
from qcanvas.util.course_indexer import DataManager
|
|
24
|
-
from qcanvas.util.helpers import theme_helper
|
|
25
|
-
from qcanvas.util.link_scanner import CanvasFileScanner
|
|
26
|
-
from qcanvas.util.link_scanner.canvas_media_object_scanner import CanvasMediaObjectScanner
|
|
27
|
-
from qcanvas.util.link_scanner.dropbox_scanner import DropboxScanner
|
|
28
|
-
|
|
29
|
-
engine = create_async_engine("sqlite+aiosqlite:///canvas_db.😘", echo=False)
|
|
30
|
-
|
|
31
|
-
logging.basicConfig()
|
|
32
|
-
logging.getLogger("canvas_client").setLevel(logging.DEBUG)
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
class LoaderWindow(QMainWindow):
|
|
36
|
-
"""
|
|
37
|
-
Responsible for verifying that the api key and canvas url is valid, then starting the main app.
|
|
38
|
-
"""
|
|
39
|
-
init = Signal()
|
|
40
|
-
setup = Signal()
|
|
41
|
-
ready = Signal()
|
|
42
|
-
|
|
43
|
-
def __init__(self):
|
|
44
|
-
super().__init__()
|
|
45
|
-
self.main_window: AppMainWindow | None = None
|
|
46
|
-
self.main_icon = QPixmap(":/main_icon.svg")
|
|
47
|
-
|
|
48
|
-
self.init.connect(self.on_init)
|
|
49
|
-
self.setup.connect(self.on_setup)
|
|
50
|
-
self.ready.connect(self.on_ready)
|
|
51
|
-
|
|
52
|
-
self.setWindowTitle(app_name)
|
|
53
|
-
self.setWindowIcon(self.main_icon)
|
|
54
|
-
self.setCentralWidget(QProgressDialog("Verifying config", None, 0, 0))
|
|
55
|
-
|
|
56
|
-
self.init.emit()
|
|
57
|
-
|
|
58
|
-
@asyncSlot()
|
|
59
|
-
async def on_init(self) -> None:
|
|
60
|
-
try:
|
|
61
|
-
all_set = None not in [settings.api_key, settings.canvas_url, settings.panopto_url]
|
|
62
|
-
# Verify that the canvas urls and api key are valid
|
|
63
|
-
if not all_set:
|
|
64
|
-
# Show the setup dialog
|
|
65
|
-
self.setup.emit()
|
|
66
|
-
else:
|
|
67
|
-
# Proceed to main app
|
|
68
|
-
self.ready.emit()
|
|
69
|
-
except:
|
|
70
|
-
# If a problem occurred then something is probably invalid
|
|
71
|
-
self.setup.emit()
|
|
72
|
-
|
|
73
|
-
@asyncSlot()
|
|
74
|
-
async def on_setup(self) -> None:
|
|
75
|
-
"""
|
|
76
|
-
Shows the setup dialog
|
|
77
|
-
"""
|
|
78
|
-
setup = SetupDialog(self, allow_cancel=False)
|
|
79
|
-
setup.setWindowIcon(self.main_icon)
|
|
80
|
-
setup.rejected.connect(lambda: self.close())
|
|
81
|
-
setup.accepted.connect(self.on_ready)
|
|
82
|
-
setup.show()
|
|
83
|
-
|
|
84
|
-
@asyncSlot()
|
|
85
|
-
async def on_ready(self) -> None:
|
|
86
|
-
"""
|
|
87
|
-
Sets up the canvas client and data manager for the main app
|
|
88
|
-
"""
|
|
89
|
-
client = CanvasClient(canvas_url=URL(settings.canvas_url), api_key=settings.api_key)
|
|
90
|
-
data_manager = DataManager(
|
|
91
|
-
client=client,
|
|
92
|
-
link_scanners=[
|
|
93
|
-
CanvasFileScanner(client),
|
|
94
|
-
DropboxScanner(httpx.AsyncClient()),
|
|
95
|
-
CanvasMediaObjectScanner(client.client)
|
|
96
|
-
],
|
|
97
|
-
# Don't expire on commit because we need to take objects outside of the session
|
|
98
|
-
sessionmaker=AsyncSessionMaker(engine, expire_on_commit=False)
|
|
99
|
-
)
|
|
100
|
-
|
|
101
|
-
await data_manager.init()
|
|
102
|
-
self.close()
|
|
103
|
-
self.open_main_app(data_manager)
|
|
104
|
-
|
|
105
|
-
def open_main_app(self, data_manager: DataManager) -> None:
|
|
106
|
-
"""
|
|
107
|
-
Starts the main app
|
|
108
|
-
Parameters
|
|
109
|
-
----------
|
|
110
|
-
data_manager
|
|
111
|
-
The data manager the app will use
|
|
112
|
-
"""
|
|
113
|
-
|
|
114
|
-
self.main_window = AppMainWindow(data_manager)
|
|
115
|
-
self.main_window.setWindowTitle(app_name)
|
|
116
|
-
self.main_window.setWindowIcon(self.main_icon)
|
|
117
|
-
self.main_window.show()
|
|
118
|
-
# Set the main window as the parent of this window so this window is destroyed when the main window is closed
|
|
119
|
-
self.setParent(self.main_window)
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
async def setup_db():
|
|
123
|
-
# Create meta stuff
|
|
124
|
-
async with engine.begin() as conn:
|
|
125
|
-
await conn.run_sync(db.Base.metadata.create_all)
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
if __name__ == '__main__':
|
|
129
|
-
asyncio.run(setup_db())
|
|
130
|
-
|
|
131
|
-
app = QApplication(sys.argv)
|
|
132
|
-
|
|
133
|
-
# Apply the selected theme to qt
|
|
134
|
-
theme_helper.apply_selected_theme()
|
|
135
|
-
|
|
136
|
-
# Setup event loop for qasync
|
|
137
|
-
event_loop = QEventLoop()
|
|
138
|
-
asyncio.set_event_loop(event_loop)
|
|
139
|
-
app_close_event = asyncio.Event()
|
|
140
|
-
app.aboutToQuit.connect(app_close_event.set)
|
|
141
|
-
|
|
142
|
-
# Start the loader, which verifies the client config and initialises the data manager for the main program
|
|
143
|
-
loader_window = LoaderWindow()
|
|
144
|
-
loader_window.show()
|
|
145
|
-
|
|
146
|
-
# For qasync
|
|
147
|
-
with event_loop:
|
|
148
|
-
event_loop.run_until_complete(app_close_event.wait())
|
|
149
|
-
|
|
150
|
-
print("Exiting")
|
|
151
|
-
|
|
152
|
-
# Pass the 'restart needed' flag back to the launcher script, which will re-run the program.
|
|
153
|
-
# See self_updater.do_update
|
|
154
|
-
if self_updater.restart_flag:
|
|
155
|
-
sys.exit(updated_and_needs_restart_return_code)
|
qcanvas/db/__init__.py
DELETED
|
@@ -1,5 +0,0 @@
|
|
|
1
|
-
from .database import Resource, Module, ModuleItem, ModulePage, ModuleFile, ResourceState, Course, Term, \
|
|
2
|
-
Assignment, Base, PageLike, ResourceToModuleItemAssociation, ResourceToAssignmentAssociation, CoursePreferences, \
|
|
3
|
-
GroupByPreference
|
|
4
|
-
from .db_converter_helper import convert_course, convert_page, convert_file, convert_legacy_file, \
|
|
5
|
-
convert_assignment, convert_module, convert_term, convert_file_page
|
qcanvas/db/database.py
DELETED
|
@@ -1,338 +0,0 @@
|
|
|
1
|
-
import os.path
|
|
2
|
-
import pathlib
|
|
3
|
-
import platform
|
|
4
|
-
import re
|
|
5
|
-
from datetime import datetime
|
|
6
|
-
from enum import Enum
|
|
7
|
-
from typing import List, Optional, MutableSequence
|
|
8
|
-
|
|
9
|
-
from sqlalchemy import ForeignKey, Text
|
|
10
|
-
from sqlalchemy.ext.asyncio import AsyncAttrs
|
|
11
|
-
from sqlalchemy.orm import DeclarativeBase, mapped_column, Mapped, relationship, MappedAsDataclass
|
|
12
|
-
|
|
13
|
-
import qcanvas.util.tree_util as tree
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
class PageLike:
|
|
17
|
-
@property
|
|
18
|
-
def content(self) -> str | None:
|
|
19
|
-
raise NotImplementedError()
|
|
20
|
-
|
|
21
|
-
@property
|
|
22
|
-
def name(self) -> str:
|
|
23
|
-
raise NotImplementedError()
|
|
24
|
-
|
|
25
|
-
@property
|
|
26
|
-
def id(self) -> str:
|
|
27
|
-
raise NotImplementedError()
|
|
28
|
-
|
|
29
|
-
@property
|
|
30
|
-
def resources(self) -> MutableSequence["Resource"]:
|
|
31
|
-
raise NotImplementedError()
|
|
32
|
-
|
|
33
|
-
@property
|
|
34
|
-
def course_id(self) -> str:
|
|
35
|
-
raise NotImplementedError()
|
|
36
|
-
|
|
37
|
-
@course_id.setter
|
|
38
|
-
def course_id(self, value: str):
|
|
39
|
-
raise NotImplementedError()
|
|
40
|
-
|
|
41
|
-
@property
|
|
42
|
-
def updated_at(self) -> datetime:
|
|
43
|
-
raise NotImplementedError()
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
class Base(AsyncAttrs, DeclarativeBase):
|
|
47
|
-
pass
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
def default_assignment_module(module: "Module") -> bool:
|
|
51
|
-
result = module.name.lower() in ["assessments", "assessment"]
|
|
52
|
-
|
|
53
|
-
return result
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
class GroupByPreference(Enum):
|
|
57
|
-
GROUP_BY_PAGES = 0
|
|
58
|
-
GROUP_BY_MODULES = 1
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
# fixme should this be MappedAsDataclass?
|
|
62
|
-
class CoursePreferences(Base):
|
|
63
|
-
__tablename__ = "preferences"
|
|
64
|
-
|
|
65
|
-
id: Mapped[int] = mapped_column(primary_key=True, autoincrement=True)
|
|
66
|
-
|
|
67
|
-
local_name: Mapped[Optional[str]]
|
|
68
|
-
files_group_by_preference: Mapped["GroupByPreference"] = mapped_column(default=GroupByPreference.GROUP_BY_PAGES)
|
|
69
|
-
|
|
70
|
-
course_id: Mapped[str] = mapped_column(ForeignKey("courses.id"))
|
|
71
|
-
course: Mapped["Course"] = relationship(back_populates="preferences")
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
class Course(MappedAsDataclass, Base, init=False):
|
|
75
|
-
__tablename__ = "courses"
|
|
76
|
-
|
|
77
|
-
id: Mapped[str] = mapped_column(primary_key=True)
|
|
78
|
-
|
|
79
|
-
term_id: Mapped[str] = mapped_column(ForeignKey("terms.id"))
|
|
80
|
-
term: Mapped["Term"] = relationship(back_populates="courses")
|
|
81
|
-
|
|
82
|
-
preferences: Mapped["CoursePreferences"] = relationship(back_populates="course")
|
|
83
|
-
|
|
84
|
-
name: Mapped[str]
|
|
85
|
-
|
|
86
|
-
modules: Mapped[List["Module"]] = relationship(back_populates="course")
|
|
87
|
-
module_items: Mapped[List["ModuleItem"]] = relationship(back_populates="course")
|
|
88
|
-
assignments: Mapped[List["Assignment"]] = relationship(back_populates="course")
|
|
89
|
-
resources: Mapped[List["Resource"]] = relationship(back_populates="course")
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
class Term(MappedAsDataclass, Base):
|
|
93
|
-
"""
|
|
94
|
-
A term object.
|
|
95
|
-
Each course belongs to a term.
|
|
96
|
-
|
|
97
|
-
Attributes
|
|
98
|
-
----------
|
|
99
|
-
name: str
|
|
100
|
-
Name of the term
|
|
101
|
-
start_at: Optional[datetime]
|
|
102
|
-
Date the term starts
|
|
103
|
-
Will be null for the 'default term'.
|
|
104
|
-
end_at: Optional[datetime]
|
|
105
|
-
Date the term ends.
|
|
106
|
-
Will be null for the 'default term'.
|
|
107
|
-
courses: list[Course]
|
|
108
|
-
*Not required in constructor.*
|
|
109
|
-
List of courses that belong to this term.
|
|
110
|
-
"""
|
|
111
|
-
|
|
112
|
-
__tablename__ = "terms"
|
|
113
|
-
id: Mapped[str] = mapped_column(primary_key=True)
|
|
114
|
-
|
|
115
|
-
end_at: Mapped[Optional[datetime]]
|
|
116
|
-
start_at: Mapped[Optional[datetime]]
|
|
117
|
-
name: Mapped[str]
|
|
118
|
-
|
|
119
|
-
courses: Mapped[List["Course"]] = relationship(back_populates="term", cascade="all, delete")
|
|
120
|
-
|
|
121
|
-
def __init__(self, id: str, name: str, end_at: Optional[datetime], start_at: Optional[datetime]):
|
|
122
|
-
super().__init__()
|
|
123
|
-
self.id = id
|
|
124
|
-
self.name = name
|
|
125
|
-
self.end_at = end_at
|
|
126
|
-
self.start_at = start_at
|
|
127
|
-
|
|
128
|
-
def __hash__(self):
|
|
129
|
-
return hash(self.id) ^ hash(self.end_at) ^ hash(self.start_at) ^ hash(self.name)
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
class Module(MappedAsDataclass, Base, tree.HasText, init=False):
|
|
133
|
-
__tablename__ = "modules"
|
|
134
|
-
id: Mapped[str] = mapped_column(primary_key=True)
|
|
135
|
-
|
|
136
|
-
course_id: Mapped[str] = mapped_column(ForeignKey("courses.id"))
|
|
137
|
-
course: Mapped["Course"] = relationship(back_populates="modules")
|
|
138
|
-
|
|
139
|
-
name: Mapped[str]
|
|
140
|
-
|
|
141
|
-
items: Mapped[List["ModuleItem"]] = relationship(back_populates="module", order_by="ModuleItem.position")
|
|
142
|
-
|
|
143
|
-
@property
|
|
144
|
-
def text(self) -> str:
|
|
145
|
-
return self.name
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
class ResourceToModuleItemAssociation(MappedAsDataclass, Base):
|
|
149
|
-
__tablename__ = "resource_to_moduleitem"
|
|
150
|
-
module_item_id: Mapped[str] = mapped_column(ForeignKey("module_items.id"), primary_key=True)
|
|
151
|
-
resource_id: Mapped[str] = mapped_column(ForeignKey("resources.id"), primary_key=True)
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
class ResourceToAssignmentAssociation(MappedAsDataclass, Base):
|
|
155
|
-
__tablename__ = "resource_to_assignment"
|
|
156
|
-
assignment_id: Mapped[str] = mapped_column(ForeignKey("assignments.id"), primary_key=True)
|
|
157
|
-
resource_id: Mapped[str] = mapped_column(ForeignKey("resources.id"), primary_key=True)
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
class ResourceState(Enum):
|
|
161
|
-
NOT_DOWNLOADED = 0
|
|
162
|
-
DOWNLOADED = 1
|
|
163
|
-
FAILED = 2
|
|
164
|
-
|
|
165
|
-
@staticmethod
|
|
166
|
-
def human_readable(value: "ResourceState"):
|
|
167
|
-
match value:
|
|
168
|
-
case ResourceState.NOT_DOWNLOADED:
|
|
169
|
-
return "Not downloaded"
|
|
170
|
-
case ResourceState.DOWNLOADED:
|
|
171
|
-
return "Downloaded"
|
|
172
|
-
case ResourceState.FAILED:
|
|
173
|
-
return "Failed"
|
|
174
|
-
|
|
175
|
-
raise ValueError(value)
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
class Resource(MappedAsDataclass, Base, tree.HasText):
|
|
179
|
-
__tablename__ = "resources"
|
|
180
|
-
id: Mapped[str] = mapped_column(primary_key=True)
|
|
181
|
-
|
|
182
|
-
course_id: Mapped[str] = mapped_column(ForeignKey("courses.id"))
|
|
183
|
-
course: Mapped["Course"] = relationship(back_populates="resources")
|
|
184
|
-
|
|
185
|
-
url: Mapped[str]
|
|
186
|
-
file_name: Mapped[str] # Human-readable name
|
|
187
|
-
file_size: Mapped[int]
|
|
188
|
-
state: Mapped[ResourceState]
|
|
189
|
-
fail_message: Mapped[Optional[str]]
|
|
190
|
-
date_discovered: Mapped[datetime]
|
|
191
|
-
|
|
192
|
-
module_items: Mapped[List["ModuleItem"]] = relationship(secondary=ResourceToModuleItemAssociation.__table__,
|
|
193
|
-
back_populates="resources", order_by="ModuleItem.position")
|
|
194
|
-
assignments: Mapped[List["Assignment"]] = relationship(secondary=ResourceToAssignmentAssociation.__table__,
|
|
195
|
-
back_populates="resources")
|
|
196
|
-
|
|
197
|
-
def __init__(self, id: str, url: str, file_name: str, file_size: int,
|
|
198
|
-
date_discovered: datetime = datetime.now(),
|
|
199
|
-
fail_message: Optional[str] = None, state=ResourceState.NOT_DOWNLOADED):
|
|
200
|
-
super().__init__()
|
|
201
|
-
self.id = id
|
|
202
|
-
self.url = url
|
|
203
|
-
self.file_name = file_name
|
|
204
|
-
self.file_size = file_size
|
|
205
|
-
self.fail_message = fail_message
|
|
206
|
-
self.state = state
|
|
207
|
-
self.date_discovered = date_discovered
|
|
208
|
-
|
|
209
|
-
def __eq__(self, __value):
|
|
210
|
-
if isinstance(__value, ModulePage):
|
|
211
|
-
return self.id == __value.id
|
|
212
|
-
else:
|
|
213
|
-
return super().__eq__(__value)
|
|
214
|
-
|
|
215
|
-
@property
|
|
216
|
-
def text(self) -> str:
|
|
217
|
-
return self.file_name
|
|
218
|
-
|
|
219
|
-
@property
|
|
220
|
-
def download_location(self) -> pathlib.Path:
|
|
221
|
-
file_id: str = self.id
|
|
222
|
-
|
|
223
|
-
# Colon is illegal in microsoft windows file names
|
|
224
|
-
if platform.system() == "Windows":
|
|
225
|
-
file_id = file_id.replace(':', '$')
|
|
226
|
-
|
|
227
|
-
file_name, file_extension = os.path.splitext(self.file_name)
|
|
228
|
-
|
|
229
|
-
return pathlib.Path("download", self._sanitise_course_name(self.course.name),
|
|
230
|
-
f"{file_name} [{file_id}]{file_extension}")
|
|
231
|
-
|
|
232
|
-
@staticmethod
|
|
233
|
-
def _sanitise_course_name(name: str) -> str:
|
|
234
|
-
return re.sub("[/\\\\<>:\"?|*]", "_", name)
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
class ModuleItem(MappedAsDataclass, Base, tree.HasText):
|
|
238
|
-
__tablename__ = "module_items"
|
|
239
|
-
|
|
240
|
-
id: Mapped[str] = mapped_column(primary_key=True)
|
|
241
|
-
|
|
242
|
-
module_id: Mapped[str] = mapped_column(ForeignKey("modules.id"))
|
|
243
|
-
module: Mapped["Module"] = relationship(back_populates="items")
|
|
244
|
-
|
|
245
|
-
course_id: Mapped[str] = mapped_column(ForeignKey("courses.id"))
|
|
246
|
-
course: Mapped["Course"] = relationship(back_populates="module_items")
|
|
247
|
-
|
|
248
|
-
created_at: Mapped[datetime]
|
|
249
|
-
updated_at: Mapped[datetime]
|
|
250
|
-
name: Mapped[str]
|
|
251
|
-
position: Mapped[int]
|
|
252
|
-
type: Mapped[str]
|
|
253
|
-
|
|
254
|
-
resources: Mapped[List["Resource"]] = relationship(secondary=ResourceToModuleItemAssociation.__table__,
|
|
255
|
-
back_populates="module_items")
|
|
256
|
-
|
|
257
|
-
__mapper_args__ = {
|
|
258
|
-
"polymorphic_identity": "module_item",
|
|
259
|
-
"polymorphic_on": "type",
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
def __init__(self, id: str, created_at: datetime, updated_at: datetime, name: str):
|
|
263
|
-
super().__init__()
|
|
264
|
-
|
|
265
|
-
self.id = id
|
|
266
|
-
self.created_at = created_at
|
|
267
|
-
self.updated_at = updated_at
|
|
268
|
-
self.name = name
|
|
269
|
-
|
|
270
|
-
@property
|
|
271
|
-
def text(self) -> str:
|
|
272
|
-
return self.name
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
class ModuleFile(ModuleItem):
|
|
276
|
-
__tablename__ = "module_files"
|
|
277
|
-
|
|
278
|
-
id: Mapped[str] = mapped_column(ForeignKey("module_items.id"), primary_key=True)
|
|
279
|
-
|
|
280
|
-
__mapper_args__ = {
|
|
281
|
-
"polymorphic_identity": "module_file",
|
|
282
|
-
}
|
|
283
|
-
|
|
284
|
-
def __init__(self, id: str, created_at: datetime, updated_at: datetime, name: str):
|
|
285
|
-
super().__init__(id, created_at, updated_at, name)
|
|
286
|
-
|
|
287
|
-
self.id = id
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
class ModulePage(ModuleItem, PageLike):
|
|
291
|
-
__tablename__ = "module_pages"
|
|
292
|
-
|
|
293
|
-
id: Mapped[str] = mapped_column(ForeignKey("module_items.id"), primary_key=True)
|
|
294
|
-
|
|
295
|
-
content: Mapped[str] = mapped_column()
|
|
296
|
-
|
|
297
|
-
__mapper_args__ = {
|
|
298
|
-
"polymorphic_identity": "module_page",
|
|
299
|
-
}
|
|
300
|
-
|
|
301
|
-
def __init__(self, id: str, created_at: datetime, updated_at: datetime, name: str, content: str = "Not loaded"):
|
|
302
|
-
super().__init__(id, created_at, updated_at, name)
|
|
303
|
-
|
|
304
|
-
self.id = id
|
|
305
|
-
self.content = content
|
|
306
|
-
|
|
307
|
-
def __eq__(self, __value):
|
|
308
|
-
if isinstance(__value, ModulePage):
|
|
309
|
-
return self.id == __value.id
|
|
310
|
-
else:
|
|
311
|
-
return super().__eq__(__value)
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
class Assignment(MappedAsDataclass, Base, PageLike, tree.HasText, init=False):
|
|
315
|
-
__tablename__ = "assignments"
|
|
316
|
-
|
|
317
|
-
id: Mapped[str] = mapped_column(primary_key=True)
|
|
318
|
-
|
|
319
|
-
course_id: Mapped[str] = mapped_column(ForeignKey("courses.id"))
|
|
320
|
-
course: Mapped["Course"] = relationship(back_populates="assignments")
|
|
321
|
-
|
|
322
|
-
name: Mapped[str]
|
|
323
|
-
description: Mapped[Optional[str]] = mapped_column(Text, repr=False)
|
|
324
|
-
due_at: Mapped[Optional[datetime]]
|
|
325
|
-
created_at: Mapped[datetime]
|
|
326
|
-
updated_at: Mapped[datetime]
|
|
327
|
-
position: Mapped[int]
|
|
328
|
-
|
|
329
|
-
resources: Mapped[List["Resource"]] = relationship(secondary=ResourceToAssignmentAssociation.__table__,
|
|
330
|
-
back_populates="assignments")
|
|
331
|
-
|
|
332
|
-
@property
|
|
333
|
-
def content(self) -> str:
|
|
334
|
-
return self.description
|
|
335
|
-
|
|
336
|
-
@property
|
|
337
|
-
def text(self) -> str:
|
|
338
|
-
return self.name
|
|
@@ -1,81 +0,0 @@
|
|
|
1
|
-
from datetime import datetime
|
|
2
|
-
|
|
3
|
-
import qcanvas.db.database as db
|
|
4
|
-
import qcanvas.queries as gql
|
|
5
|
-
from qcanvas.net.canvas.legacy_canvas_types import LegacyFile
|
|
6
|
-
from qcanvas.util.helpers.canvas_sanitiser import remove_garbage_from_title as clean_string
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
def convert_term(term: gql.Term) -> db.Term:
|
|
10
|
-
return db.Term(
|
|
11
|
-
id=term.q_id,
|
|
12
|
-
name=clean_string(term.name),
|
|
13
|
-
start_at=term.start_at,
|
|
14
|
-
end_at=term.end_at
|
|
15
|
-
)
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
def convert_course(course: gql.Course) -> db.Course:
|
|
19
|
-
return db.Course(
|
|
20
|
-
id=course.m_id,
|
|
21
|
-
name=clean_string(course.name),
|
|
22
|
-
local_name=clean_string(course.course_nickname)
|
|
23
|
-
)
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
def convert_assignment(assignment: gql.Assignment) -> db.Assignment:
|
|
27
|
-
return db.Assignment(
|
|
28
|
-
id=assignment.q_id,
|
|
29
|
-
name=clean_string(assignment.name),
|
|
30
|
-
description=assignment.description,
|
|
31
|
-
due_at=assignment.due_at,
|
|
32
|
-
created_at=assignment.created_at,
|
|
33
|
-
updated_at=assignment.updated_at,
|
|
34
|
-
position=assignment.position
|
|
35
|
-
)
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
def convert_page(page: gql.Page, content: str) -> db.ModulePage:
|
|
39
|
-
return db.ModulePage(
|
|
40
|
-
id=page.m_id,
|
|
41
|
-
content=content,
|
|
42
|
-
created_at=page.created_at,
|
|
43
|
-
updated_at=page.updated_at,
|
|
44
|
-
name=clean_string(page.title)
|
|
45
|
-
)
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
def convert_file_page(file: gql.File) -> db.ModuleFile:
|
|
49
|
-
return db.ModuleFile(
|
|
50
|
-
id=file.m_id,
|
|
51
|
-
created_at=file.created_at,
|
|
52
|
-
updated_at=file.updated_at,
|
|
53
|
-
name=clean_string(file.display_name)
|
|
54
|
-
)
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
def convert_file(file: gql.File, file_size: int) -> db.Resource:
|
|
58
|
-
return db.Resource(
|
|
59
|
-
id=str(file.m_id),
|
|
60
|
-
url=file.url,
|
|
61
|
-
file_name=clean_string(file.display_name),
|
|
62
|
-
date_discovered=datetime.now(),
|
|
63
|
-
file_size=file_size
|
|
64
|
-
)
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
def convert_legacy_file(file: LegacyFile) -> db.Resource:
|
|
68
|
-
return db.Resource(
|
|
69
|
-
id=str(file.id),
|
|
70
|
-
url=file.url,
|
|
71
|
-
file_name=clean_string(file.display_name),
|
|
72
|
-
date_discovered=datetime.now(),
|
|
73
|
-
file_size=file.size
|
|
74
|
-
)
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
def convert_module(module: gql.Module) -> db.Module:
|
|
78
|
-
return db.Module(
|
|
79
|
-
id=module.q_id,
|
|
80
|
-
name=clean_string(module.name)
|
|
81
|
-
)
|
qcanvas/net/canvas/__init__.py
DELETED