diff --git a/source/utils/__init__.py b/source/utils/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/source/utils/compress.py b/source/utils/compress.py new file mode 100644 index 0000000..5068222 --- /dev/null +++ b/source/utils/compress.py @@ -0,0 +1,22 @@ +import json +import zlib + + +def compress_data(data: dict) -> bytes: + """ + Serialize to json and compress a data dictionary + :param data: the data to compress + :return: the data as a dictionnary + """ + + return zlib.compress(json.dumps(data, ensure_ascii=False).encode("utf-8")) + + +def uncompress_data(data: bytes) -> dict: + """ + Decompress and deserialize from json a data dictionary + :param data: the data to decompress + :return: the compressed data + """ + + return json.loads(zlib.decompress(data)) diff --git a/source/widget/SavingScreen.py b/source/widget/SavingScreen.py new file mode 100644 index 0000000..75db699 --- /dev/null +++ b/source/widget/SavingScreen.py @@ -0,0 +1,100 @@ +import typing +import uuid +from io import BytesIO +from pathlib import Path +from typing import Optional + +import nextcord +import requests +from PyQt6.QtCore import Qt, QThread +from PyQt6.QtGui import QFont +from PyQt6.QtWidgets import QWidget, QProgressBar, QVBoxLayout, QLabel, QMessageBox + +from source import widget +from source.utils.compress import compress_data + + +result_path = Path("./results/") + + +class SavingScreen(QWidget): + def __init__( + self, + collected_datas: dict, + discord_webhook_url: Optional[str] = None + ): + super().__init__() + + self.compressed_collected_datas = compress_data(collected_datas) + self.discord_webhook_url = discord_webhook_url + + # layout + self._layout = QVBoxLayout() + self.setLayout(self._layout) + + # prepare the title + self.label_title = QLabel() + self._layout.addWidget(self.label_title) + self.label_title.setText(self.tr("UPLOADING DATA")) + self.label_title.setAlignment(Qt.AlignmentFlag.AlignCenter) + + font_title = self.label_title.font() + font_title.setPointSize(24) + font_title.setWeight(QFont.Weight.Bold) + self.label_title.setFont(font_title) + + # progress + self.progress = QProgressBar() + self._layout.addWidget(self.progress) + + # prepare the filename + filename: str = f"{uuid.uuid4()}.rsl" + + # start a thread for the saving + thread = QThread() + thread.started.connect(lambda: self.save(filename)) # NOQA: connect exist + thread.start() + + def save(self, filename: str): + # save to a file + self.result_save_file(filename) + + # upload to a discord webhook + if self.discord_webhook_url is not None: + try: + self.result_upload_discord(filename) + except nextcord.HTTPException: + # if there is an error while uploading, show a graphical warning to the user + QMessageBox.warning( + self, + title=self.tr("WARNING"), + text=self.tr("COULD NOT UPLOAD TO DISCORD, SEND MANUALLY"), + ) + + # quit the application + window = typing.cast(widget.SurveyWindow, self.window()) + window.quit() + + def result_save_file(self, filename: str) -> None: + """ + Save the result data to a file + """ + + result_path.mkdir(parents=True, exist_ok=True) + (result_path / filename).write_bytes(self.compressed_collected_datas) + + def result_upload_discord(self, filename: str) -> None: + """ + Upload the result to a discord webhook + """ + + # create a session + with requests.Session() as session: + # load the configured webhook + webhook = nextcord.SyncWebhook.from_url(self.discord_webhook_url, session=session) + + # send the message to discord + message = webhook.send( + file=nextcord.File(fp=BytesIO(self.compressed_collected_datas), filename=filename), + wait=True + ) diff --git a/source/widget/SurveyEngine.py b/source/widget/SurveyEngine.py index 043463f..8308685 100644 --- a/source/widget/SurveyEngine.py +++ b/source/widget/SurveyEngine.py @@ -1,25 +1,17 @@ import json import time -import uuid -import zlib -from io import BytesIO +import typing from pathlib import Path from typing import Optional -import nextcord -import requests from PyQt6.QtCore import pyqtSignal from PyQt6.QtWidgets import QVBoxLayout, QProgressBar, QWidget -from source import translate +from source import translate, widget from source.survey.base import BaseSurvey from source.survey import Empty, survey_get -result_path = Path("./results/") -result_path.mkdir(parents=True, exist_ok=True) - - class SurveyEngine(QWidget): signal_abandon = pyqtSignal() signal_skip = pyqtSignal() @@ -95,7 +87,8 @@ class SurveyEngine(QWidget): def _on_signal_abandon(self): # on abandon, quit the survey - self.quit() + window = typing.cast(widget.SurveyWindow, self.window()) + window.quit() def _on_signal_skip(self): # on skip, skip to the next survey @@ -152,61 +145,12 @@ class SurveyEngine(QWidget): self.survey.on_ready() def finish_survey(self): - # TODO: page with indication and progress bar for upload + saving_screen = widget.SavingScreen( + self.collected_datas, + self.discord_webhook_result_url + ) - filename: str = f"{uuid.uuid4()}.rsl" + window = typing.cast(widget.SurveyWindow, self.window()) + window.setCentralWidget(saving_screen) - # save the result in a local file - self.result_save_file(result_path / filename) - - # if set, try to send the result to a discord webhook - if self.discord_webhook_result_url is not None: - try: - self.result_upload_discord(filename=filename) - except nextcord.HTTPException: - # TODO: say to send manually the local file - raise - - self.quit() - - def get_result_data(self) -> bytes: - """ - Return the compressed result data - """ - - return zlib.compress(json.dumps(self.collected_datas, ensure_ascii=False).encode("utf-8")) - - def result_save_file(self, destination: Path | str) -> None: - """ - Save the result data to a file - :param destination: the path to the file - """ - - with open(destination, "wb") as file: - file.write(self.get_result_data()) - - def result_upload_discord(self, filename: str = "result.rsl") -> None: - """ - Upload the result to a discord webhook - """ - - # create a session - with requests.Session() as session: - # load the configured webhook - webhook = nextcord.SyncWebhook.from_url( - self.discord_webhook_result_url, - session=session - ) - - # send the message to discord - message = webhook.send( - file=nextcord.File( - fp=BytesIO(self.get_result_data()), - filename=filename), - wait=True - ) - - def quit(self): - # quit the application by closing and deleting the window - self.window().close() - self.window().deleteLater() + self.deleteLater() diff --git a/source/widget/SurveyWindow.py b/source/widget/SurveyWindow.py index c15b06c..2e10612 100644 --- a/source/widget/SurveyWindow.py +++ b/source/widget/SurveyWindow.py @@ -17,3 +17,8 @@ class SurveyWindow(QMainWindow): self.setWindowTitle(self.tr("SURVEY")) self.setCentralWidget(widget.SurveyEngine.from_file(survey_path)) + + def quit(self): + # quit the application by closing and deleting the window + self.window().close() + self.window().deleteLater() \ No newline at end of file diff --git a/source/widget/__init__.py b/source/widget/__init__.py index b96e266..c23eaaa 100644 --- a/source/widget/__init__.py +++ b/source/widget/__init__.py @@ -2,3 +2,4 @@ from .Browser import Browser from .SurveyEngine import SurveyEngine from .SurveyWindow import SurveyWindow from .SurveyNavigation import SurveyNavigation +from .SavingScreen import SavingScreen diff --git a/surveys.json b/surveys.json index 8b49f43..436a67e 100644 --- a/surveys.json +++ b/surveys.json @@ -445,9 +445,9 @@ "sp": "Agradecimientos" }, "description": { - "en": "We greatly appreciate your contribution to our survey and your time.\n\nYour collected data is located in the \"results\" folder.", - "fr": "Nous vous remercions grandement pour votre contribution à notre questionnaire et pour votre temps.\n\nVos données collectées sont situées dans le dossier \"results\".", - "sp": "Agradecemos enormemente su contribución a nuestro cuestionario y su tiempo.\n\nSus datos recopilados se encuentran en la carpeta \"results\"." + "en": "We greatly appreciate your contribution to our survey and your time.", + "fr": "Nous vous remercions grandement pour votre contribution à notre questionnaire et pour votre temps.", + "sp": "Agradecemos enormemente su contribución a nuestro cuestionario y su tiempo." } } }